package com.eslserver.servletapi;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.esl.coordinator.command.Command;
import com.esl.coordinator.command.CommandInvoker;
import com.esl.coordinator.command.CommandReceiver;
import com.esl.coordinator.command.STiTEQATMELCommandFactory;
import com.esl.coordinator.command.SocketCommandReceiver;
import com.esl.coordinator.exception.ImageSizeMismatchException;
import com.esl.coordinator.exception.STiTEQATMELIntegrationException;
import com.esl.coordinator.util.BMP;
import com.eslserver.servletapi.input.PushESLServletInputParam;
import com.eslserver.servletapi.response.PushESLDisplayReturnValue;
import com.eslserver.servletapi.timer.CommandRetryJob;

@SuppressWarnings("serial")
public class PushESLDisplayServlet extends HttpServlet implements
		PushESLServletInputParam, PushESLDisplayReturnValue {
	public static final Logger LOG = LoggerFactory
			.getLogger(PushESLDisplayServlet.class);

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		if (!ServletFileUpload.isMultipartContent(req)) {
			throw new IllegalArgumentException(
					"Request is not multipart, please 'multipart/form-data' enctype for your form.");
		}

		ServletFileUpload uploadHandler = new ServletFileUpload(
				new DiskFileItemFactory());
		String returnMessage = new String(OK);
		PrintWriter pw = resp.getWriter();

		PushESLServletInputWrapper pushESLServletInputWrapper = new PushESLServletInputWrapper();

		try {
			@SuppressWarnings("unchecked")
			List<FileItem> items = uploadHandler.parseRequest(req);

			for (FileItem item : items) {
				if (item.isFormField()) {
					String fieldName = item.getFieldName();
					String fieldValue = item.getString();
					if (fieldName.equals(ESL_MAC_ADDRESS)) {
						pushESLServletInputWrapper.setEslMac(fieldValue);
					} else if (fieldName.equals(COORDINATOR_IP_ADDRESS)) {
						pushESLServletInputWrapper.setCoordinatorIp(fieldValue);
					} else if (fieldName.equals(COORDINATOR_PORT)) {
						pushESLServletInputWrapper.setCoordinatorPort(Integer
								.valueOf(fieldValue));
					} else if (fieldName.equals(ESL_SLEEP_TIME)) {
						pushESLServletInputWrapper.setEslSleepTime(Integer
								.valueOf(fieldValue));
					}
				}
			}

			for (FileItem item : items) {
				if (!item.isFormField()) {
					boolean isretry = false;
					CommandReceiver commandReceiver = SocketCommandReceiver
							.getInstance(pushESLServletInputWrapper
									.getCoordinatorIp(),
									pushESLServletInputWrapper
											.getCoordinatorPort());

					byte[] imageBytes = item.get();
					Command pushCommand = STiTEQATMELCommandFactory
							.getInstance().createLCDImageDataTransferCommand(
									pushESLServletInputWrapper.getEslMac(),
									BMP.toByteArrayNoPadding(imageBytes),
									commandReceiver);

					try {
						CommandInvoker.sendCommand(pushCommand);

						if (pushCommand.isCommandSuccessful()) {
							if (pushESLServletInputWrapper.getEslSleepTime() != null
									&& pushESLServletInputWrapper
											.getEslSleepTime() > 0) {
								Command setSleepCommand = STiTEQATMELCommandFactory
										.getInstance()
										.createSetESLDeviceSleepTimeCommand(
												pushESLServletInputWrapper
														.getEslMac(),
												0,
												pushESLServletInputWrapper
														.getEslSleepTime(),
												commandReceiver);
								setSleepCommand.setThreadSleepTime(5);
								Thread thread = new Thread(new CommandInvoker(
										setSleepCommand));

								// Start the thread
								thread.start();
							}
						} else {
							returnMessage = ERROR;
							isretry = true;
						}
					} catch (ImageSizeMismatchException e) {
						LOG.error(e.getMessage(), e);
						returnMessage = INVALID_FILE;
					} catch (STiTEQATMELIntegrationException e) {
						LOG.error(e.getMessage(), e);
						returnMessage = ERROR;
						isretry = true;
					} catch (IOException e) {
						LOG.error(e.getMessage(), e);
						returnMessage = CONNECTION_FAIL;
						isretry = true;
					} finally {
						if (!pushCommand.isCommandSuccessful() && isretry) {
							CommandRetryJob.addCommand(pushCommand);
						}
					}

					break; // assume we only get one file at a time
				}
			}

			pw.write(returnMessage);
			pw.close();
		} catch (FileUploadException e) {
			returnMessage = INVALID_FILE;
		}
	}

	private class PushESLServletInputWrapper {
		private String eslMac;
		private String coordinatorIp;
		private Integer coordinatorPort;
		private Integer eslSleepTime;

		public String getEslMac() {
			return eslMac;
		}

		public void setEslMac(String eslMac) {
			this.eslMac = eslMac;
		}

		public String getCoordinatorIp() {
			return coordinatorIp;
		}

		public void setCoordinatorIp(String coordinatorIp) {
			this.coordinatorIp = coordinatorIp;
		}

		public Integer getCoordinatorPort() {
			return coordinatorPort;
		}

		public void setCoordinatorPort(Integer coordinatorPort) {
			this.coordinatorPort = coordinatorPort;
		}

		public Integer getEslSleepTime() {
			return eslSleepTime;
		}

		public void setEslSleepTime(Integer eslSleepTime) {
			this.eslSleepTime = eslSleepTime;
		}
	}

}
